import os
import sys
import subprocess
import ctypes
import tkinter as tk
from tkinter import ttk, filedialog
import pyautogui
from PIL import Image
import win32con
import win32gui
import win32api
import keyboard
import threading
import pystray
import cv2
import numpy as np
import pyautogui
import time
from datetime import datetime
import wave
import pyaudio
from threading import Event

# 新增全局变量
recording = False
paused = False
stop_event = Event()
start_time = 0
frame_rate = 20
quality = "medium"  # low, medium, high
audio_source = "none"  # none, mic, speaker, both

start_x, start_y = None, None
end_x, end_y = None, None
screenshot = None
def on_window_close():
    stop_event.set()  # 设置停止事件
    try:
        tray_icon.stop()  # 停止托盘图标
        stop_event.set()  # 设置停止事件
        root.destroy()    # 销毁主窗口
    except Exception as e:
        print(f"退出时出错: {e}")
    finally:
        os._exit(0)  # 强制退出程序
# 初始化主窗口
root = tk.Tk()
root.title("录屏截图大师")
root.protocol('WM_DELETE_WINDOW', on_window_close)  # 设置关闭协议
# 修改窗口样式，禁用最大化按钮
root.resizable(False, False)  # 禁止调整窗口大小
root.attributes('-toolwindow', False)  # 确保不是工具窗口样式

# 修改为以下方式隐藏任务栏图标而不影响窗口按钮
root.wm_attributes('-toolwindow', False)  # 确保设置为False以保留最小化按钮
root.attributes('-alpha', 0.99)  # 保持窗口样式

# 使用win32api隐藏任务栏图标
try:
    import win32gui
    import win32con
    hwnd = win32gui.GetForegroundWindow()
    win32gui.ShowWindow(hwnd, win32con.SW_HIDE)  # 先隐藏
    win32gui.ShowWindow(hwnd, win32con.SW_SHOW)  # 再显示，这样可以移除任务栏图标
except:
    pass

# 最小化到托盘处理
def minimize_to_tray(event=None):
    root.withdraw()  # 隐藏窗口

root.bind('<Unmap>', minimize_to_tray)  # 窗口最小化事件

# 将 create_audio_source_menu 函数定义移到 create_main_interface 之前
def create_audio_source_menu(root):
    frame = tk.LabelFrame(root, text="音源选择", padx=5, pady=5)
    frame.pack(padx=10, pady=5, fill=tk.X)
    
    audio_var = tk.StringVar(value=audio_source)
    
    options = [
        ("不录制声音", "none"),
        ("麦克风", "mic"),
        ("扬声器", "speaker"),
        ("麦克风和扬声器", "both")
    ]
    
    for text, mode in options:
        rb = tk.Radiobutton(
            frame, text=text, variable=audio_var,
            value=mode, command=lambda: set_audio_source(audio_var.get())
        )
        rb.pack(anchor=tk.W)
    
    return frame


def create_settings_menu(root):
    global save_interval_var
    frame = tk.LabelFrame(root, text="录制设置", padx=5, pady=5)
    frame.pack(padx=10, pady=5, fill=tk.X)
    
    # 帧率设置
    tk.Label(frame, text="帧率 (1-60):").pack(anchor=tk.W)
    frame_rate_slider = tk.Scale(
        frame, from_=1, to=60, orient=tk.HORIZONTAL,
        command=lambda v: set_frame_rate(int(v))
    )
    frame_rate_slider.set(frame_rate)
    frame_rate_slider.pack(fill=tk.X)
    
    # 清晰度设置
    tk.Label(frame, text="清晰度:").pack(anchor=tk.W)
    quality_var = tk.StringVar(value="中")  # 修改默认值为"中"而不是"medium"
    qualities = ["低", "中", "高"]
    quality_menu = ttk.Combobox(frame, textvariable=quality_var, values=qualities)
    quality_menu.pack(fill=tk.X)
    quality_menu.bind("<<ComboboxSelected>>", lambda e: set_quality(quality_var.get()))
    
    # 新增定时保存时间设置
    tk.Label(frame, text="定时保存间隔(秒)(10~3600):").pack(anchor=tk.W)
    save_interval_var = tk.StringVar(value="300")  # 默认5分钟
    
    # 验证函数 - 只允许数字输入
    def validate_input(new_value):
        if not new_value:  # 允许空值（删除操作）
            return True
        if not new_value.isdigit():  # 只允许数字
            return False
        if len(new_value) > 4:  # 限制最大长度
            return False
        return True
    
    # 注册验证命令
    vcmd = (root.register(lambda new_value: validate_input(new_value)), '%P')
    
    save_interval_entry = tk.Entry(
        frame, 
        textvariable=save_interval_var,
        validate='key',  # 在每次按键时验证
        validatecommand=vcmd
    )
    save_interval_entry.pack(fill=tk.X)
    
    # 验证输入范围
    def validate_range():
        try:
            interval = int(save_interval_var.get() or "300")
            interval = max(10, min(3600, interval))  # 限制在10-3600之间
            save_interval_var.set(str(interval))
            return interval
        except ValueError:
            save_interval_var.set("300")  # 重置为默认值
            return 300
    
    save_interval_entry.bind("<FocusOut>", lambda e: validate_range())
    
    return frame

def create_timer_display(root):
    frame = tk.LabelFrame(root, text="录制时间", padx=5, pady=5)
    frame.pack(padx=10, pady=5, fill=tk.X)
    
    time_label = tk.Label(frame, text="00:00:00", font=('Arial', 14))
    time_label.pack()
    
    return time_label

def update_timer(label):
    if recording and not paused:
        elapsed = int(time.time() - start_time)
        hours = elapsed // 3600
        minutes = (elapsed % 3600) // 60
        seconds = elapsed % 60
        label.config(text=f"{hours:02d}:{minutes:02d}:{seconds:02d}")
    label.after(1000, lambda: update_timer(label))

# 新增的录屏区域选择函数
# 在全局变量部分添加
current_file_path = None

def select_recording_area(file_path):
    global capture_window, canvas, is_recording_mode, current_file_path
    current_file_path = file_path  # 保存文件路径到全局变量
    is_recording_mode = True
    
    def create_window():
        global capture_window, canvas
        capture_window = tk.Toplevel()
        capture_window.attributes('-fullscreen', True)
        capture_window.attributes('-alpha', 0.3)
        
        canvas = tk.Canvas(capture_window)
        canvas.pack(fill=tk.BOTH, expand=True)
        rect = None
        
        def on_mouse_move(event):
            nonlocal rect
            if start_x and start_y:
                if rect:
                    canvas.delete(rect)
                rect = canvas.create_rectangle(
                        start_x, start_y, event.x_root, event.y_root,
                        outline='red', width=3
                    )
        def confirm_selection(event):
            # 获取选择的区域坐标
            x1, y1, x2, y2 = canvas.coords("selection_rect")
            width = abs(x2 - x1)
            height = abs(y2 - y1)
            
            # 检查区域是否有效
            if width < 10 or height < 10:
                print("录制区域太小")
                capture_window.destroy()
                return
                
            capture_window.destroy()
            start_actual_recording(file_path, min(x1, x2), min(y1, y2), width, height)
        
        capture_window.bind("<ButtonPress-1>", on_mouse_down)
        # 修改绑定事件的方式
        capture_window.bind("<ButtonRelease-1>", lambda e: on_mouse_up_lp(e))
        capture_window.bind("<Motion>", on_mouse_move)
        capture_window.bind("<Return>", confirm_selection)
        capture_window.bind("<Escape>", lambda e: capture_window.destroy())
        capture_window.focus_set()
    
    root.after(0, create_window)


def start_recording():
    global recording, start_time
    file_path = filedialog.asksaveasfilename(
        defaultextension=".mp4",
        filetypes=[("MP4 files", "*.mp4")]
    )
    if not file_path:
        return
    
    # 显示区域选择窗口
    select_recording_area(file_path)

# 然后定义 create_main_interface
def create_main_interface():
    # 音源选择菜单
    audio_frame = create_audio_source_menu(root)
    
    # 录制设置菜单
    settings_frame = create_settings_menu(root)
    
    # 录制时间显示
    time_label = create_timer_display(root)
    update_timer(time_label)
    
    # 修改后的创始人邮箱链接
    email_label = tk.Label(root, text="创始人邮箱: 1012828560@qq.com", fg="blue", cursor="hand2")
    email_label.pack(side=tk.TOP, anchor=tk.NE, padx=10, pady=5)
    
    def copy_email_to_clipboard(event):
        root.clipboard_clear()
        root.clipboard_append("1012828560@qq.com")
        tk.messagebox.showinfo("提示", "已将邮件地址复制到粘贴板")
    
    email_label.bind("<Double-Button-1>", copy_email_to_clipboard)
    # 新增快捷键提示标签
    hotkey_label = tk.Label(root, text="按Ctrl+Shift+Enter结束录制", font=('Arial', 10))
    hotkey_label.pack(pady=(0, 5))  # 添加在开始录制按钮上方
    
    # 开始录制按钮
    record_btn = tk.Button(root, text="开始录制", command=start_recording)
    record_btn.pack(pady=10)
    
    # 截图快捷键提示
    tip_label = tk.Label(root, text="截图快捷键: Ctrl+Shift+X", font=('Arial', 10))
    tip_label.pack()

create_main_interface()


def record_screen(out, x, y, width, height, file_path):
    global recording, paused, save_interval_var
    
    # 确保坐标和尺寸是整数
    x, y, width, height = map(int, (x, y, width, height))
    
    # 定义视频编码器
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    
    last_save_time = time.time()
    save_count = 0
    
    while recording and not stop_event.is_set():
        if not paused:
            # 捕获屏幕
            img = pyautogui.screenshot(region=(x, y, width, height))
            frame = np.array(img)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
            
            # 写入帧
            out.write(frame)
            
            # 从设置中获取保存间隔，处理空值情况
            try:
                save_interval = max(10, int(save_interval_var.get() or "300"))  # 默认300秒，最小10秒
            except ValueError:
                save_interval = 300  # 如果转换失败，使用默认值
                
            if time.time() - last_save_time >= save_interval:
                out.release()
                save_count += 1
                base_name, ext = os.path.splitext(file_path)
                new_file_path = f"{base_name}_{save_count}{ext}"
                out = cv2.VideoWriter(new_file_path, fourcc, frame_rate, (width, height))
                last_save_time = time.time()
    
    # 录制结束
    out.release()
    stop_recording()



def on_mouse_up_lp(event):
    global end_x, end_y, screenshot, start_x, start_y, current_file_path
    end_x = event.x_root
    end_y = event.y_root
    
    # 确保坐标是整数
    start_x, start_y, end_x, end_y = map(int, (start_x, start_y, end_x, end_y))
    
    # 检查区域是否有效
    if abs(end_x - start_x) < 10 or abs(end_y - start_y) < 10:
        print("区域太小")
        capture_window.destroy()
        start_x = start_y = None
        return
        
    try:
        # 获取选择的区域坐标
        x1, y1, x2, y2 = start_x, start_y, end_x, end_y
        width = abs(x2 - x1)
        height = abs(y2 - y1)
        
        # 关闭窗口
        capture_window.destroy()
        
        # 使用全局变量中的文件路径开始录屏
        start_actual_recording(current_file_path, min(x1, x2), min(y1, y2), width, height)
        
    except Exception as e:
        print(f"操作时出错: {e}")
        capture_window.destroy()
    finally:
        start_x = start_y = None

# 在全局变量部分添加
stop_hotkey_registered = False


# 新增停止录屏函数
def stop_recording():
    global recording, stop_hotkey_registered, start_time
    
    if recording:
        recording = False
        stop_hotkey_registered = False
        start_time = 0  # 重置录制时间
        
        # 刷新时间标签显示为00:00:00
        for widget in root.winfo_children():
            if isinstance(widget, tk.LabelFrame) and widget.cget("text") == "录制时间":
                for child in widget.winfo_children():
                    if isinstance(child, tk.Label):
                        child.config(text="00:00:00")
                        break
        
        # 显示提示框
        tk.messagebox.showinfo("提示", "录屏已停止并保存")
        
        try:
            keyboard.remove_hotkey('ctrl+shift+enter')
        except:
            pass

# 修改 start_actual_recording 函数
def start_actual_recording(file_path, x, y, width, height):
    global recording, start_time, stop_hotkey_registered
    
    # 注册停止热键
    if not stop_hotkey_registered:
        try:
            keyboard.add_hotkey('ctrl+shift+enter', stop_recording)
            stop_hotkey_registered = True
        except Exception as e:
            print(f"注册停止热键失败: {e}")
    
    recording = True
    start_time = time.time()
    
    # 根据清晰度设置分辨率
    if quality == "low":
        width, height = 640, 480
    elif quality == "medium":
        width, height = 1280, 720
    else:  # high
        width, height = 1920, 1080
    
    # 创建视频写入器
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    out = cv2.VideoWriter(file_path, fourcc, frame_rate, (width, height))
    
    # 开始录制线程
    threading.Thread(
        target=record_screen,
        args=(out, x, y, width, height, file_path),
        daemon=True
    ).start()

def set_frame_rate(rate):
    global frame_rate
    frame_rate = rate

def set_quality(q):
    global quality
    quality = q.lower()
    

def save_screenshot():
    if screenshot:
        file_path = filedialog.asksaveasfilename(defaultextension=".png",
                                                 filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg")])
        if file_path:
            try:
                screenshot.save(file_path)
                print(f"截图已保存到 {file_path}")
            except Exception as e:
                print(f"保存截图时出错: {e}")

# 定义鼠标拖动截屏相关函数
def on_mouse_down(event):
    global start_x, start_y, canvas  # 添加canvas到全局声明
    start_x = event.x_root
    start_y = event.y_root
    # 开始拖动时创建矩形
    canvas.delete("all")  # 清除之前的矩形
    canvas.create_rectangle(
        start_x, start_y, start_x, start_y,
        outline='red', width=3, tags="selection_rect"
    )

def on_mouse_up_jt(event):
    global end_x, end_y, screenshot, start_x, start_y  # 添加start_x, start_y
    end_x = event.x_root
    end_y = event.y_root
    
    # 检查截图区域是否有效
    if abs(end_x - start_x) < 10 or abs(end_y - start_y) < 10:
        print("截图区域太小")
        capture_window.destroy()
        start_x = start_y = None  # 重置坐标
        return
        
    try:
        # 截取矩形区域
        screenshot = pyautogui.screenshot(region=(
            min(start_x, end_x), min(start_y, end_y),
            abs(end_x - start_x), abs(end_y - start_y)
        ))
        capture_window.destroy()
        save_screenshot()
    except Exception as e:
        print(f"截图时出错: {e}")
        capture_window.destroy()
    finally:
        start_x = start_y = None  # 无论成功失败都重置坐标



# 定义全局快捷键回调函数
def capture_screenshot():
    global capture_window, canvas
    print("开始创建截屏窗口")
    
    def create_window():
        global capture_window, canvas
        capture_window = tk.Toplevel()
        capture_window.attributes('-fullscreen', True)
        capture_window.attributes('-alpha', 0.1)
        
        canvas = tk.Canvas(capture_window)
        canvas.pack(fill=tk.BOTH, expand=True)    
        
        rect = None
        
        def on_mouse_move(event):
            nonlocal rect
            if start_x and start_y:
                if rect:
                    canvas.delete(rect)
                rect = canvas.create_rectangle(
                        start_x, start_y, event.x_root, event.y_root,
                        outline='red', width=3
                    )
        
        def cancel_capture(event):
            print("取消截图")
            capture_window.destroy()
        
        capture_window.bind("<ButtonPress-1>", on_mouse_down)
        capture_window.bind("<ButtonRelease-1>", on_mouse_up_jt)
        capture_window.bind("<Motion>", on_mouse_move)
        capture_window.bind("<Escape>", cancel_capture)
        capture_window.focus_set()
    
    root.after(0, create_window)


# 全局快捷键监听函数
def hotkey_listener():
    try:
        keyboard.add_hotkey('ctrl+shift+x', lambda: root.after(0, capture_screenshot))
        print("热键注册成功! 使用Ctrl+Shift+X触发截图")
        keyboard.wait()
    except Exception as e:
        print(f"热键注册失败: {e}")
    finally:
        try:
            keyboard.remove_hotkey('ctrl+shift+x')
        except:
            pass

# 修改启动方式
def start_hotkey_listener():
    hotkey_thread = threading.Thread(target=hotkey_listener)
    hotkey_thread.daemon = True
    hotkey_thread.start()

# 隐藏控制台窗口（仅Windows有效）
try:
    import ctypes
    ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)
except:
    pass

# 修改主窗口初始化部分
def set_audio_source(source):
    global audio_source
    audio_source = source

# 启动托盘图标
def create_tray_icon():
    image = Image.new('RGB', (64, 64), color='white')
    
    menu = pystray.Menu(
        pystray.MenuItem('显示', show_window),
        pystray.MenuItem('退出', on_close)
    )
    icon = pystray.Icon("录屏截图大师", image, "录屏截图大师", menu)
    return icon

def show_window():
    root.deiconify()  # 显示窗口
    root.lift()  # 置顶窗口

def on_close():
    tray_icon.stop()
    root.quit()
tray_icon = create_tray_icon()
tray_icon.run_detached()

# 确保窗口创建完成后再启动热键监听
root.after(100, start_hotkey_listener)  # 延迟100毫秒确保窗口初始化完成

# 运行主循环
root.mainloop()
